package com.future.rabbitmq;


import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


/**
 * @author zou
 * @date 2018/8/29
 * @describe ServerEndpoint  -- WebSocket客户端建立连接的地址
 * <p>
 * 使用springboot的唯一区别是要@Component声明下，而使用独立容器是由容器自己管理websocket的，但在springboot中连容器都是spring管理的。
 * <p>
 * 虽然@Component默认是单例模式的，但springboot还是会为每个websocket连接初始化一个bean，所以可以用一个静态set保存起来。
 */
@Slf4j
@Component
@ServerEndpoint("/api/rabbit/{brandId}")
public class WebSocketServerEndpoint {

    /**
     * 存活的session集合（使用线程安全的map保存）
     */
    private static Map<String, Session> livingSessions = new ConcurrentHashMap<>();

    /**
     * 建立连接的回调方法
     *
     * @param session 与客户端的WebSocket连接会话
     * @param brandId 用户名，WebSocket支持路径参数
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("brandId") String brandId) {
        livingSessions.put(brandId + "_" + session.getId(), session);
        log.info(brandId + "进入连接");
    }

    @OnMessage
    public void onMessage(String message, @PathParam("brandId") String brandId) {
        MessageDto dto = new MessageDto();
        // todo
        sendMessageToAll(dto);
    }

    @OnError
    public void onError(Session session, Throwable error) {
        log.info("发生错误");
        log.error(error.getStackTrace() + "");
    }

    @OnClose
    public void onClose(Session session, @PathParam("brandId") String brandId) {
        livingSessions.remove(session.getId());
        log.info(brandId + " 关闭连接");
    }

    /**
     * 发送消息
     *
     * @param session
     * @param message
     */
    public void sendMessage(Session session, String message) {
        session.getAsyncRemote().sendText(message);
    }

    /**
     * 单独发送消息
     */
    public void sendMessageToPoint(MessageDto messageDto) {
        livingSessions.forEach((sessionId, session) -> {
            //发给指定的接收用户
            if (String.valueOf(sessionId).startsWith(messageDto.getReceiver().toString() + "_")) {
                if(session.isOpen()){
                    sendMessage(session, JSON.toJSONString(messageDto));
                }else {
//                     测试校验foreach remove是否有问题
                    livingSessions.remove(sessionId);
                }
            }
        });
    }

    /**
     * 群发消息
     */
    public void sendMessageToAll(MessageDto messageDto) {
        livingSessions.forEach((sessionId, session) -> {
            if(session.isOpen()) {
                sendMessage(session, JSON.toJSONString(messageDto));
            }else {
                livingSessions.remove(sessionId);
            }
        });
    }

}
